/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include "GameManager.h"
#include "Kernel.h"
#include "IGameState.h"

extern Kernel *g_kernel;

// set the id counter
type_id     IGameState::ID_TRACKER = 0;

GameManager::GameManager(void)
{
    m_current           = "";
    m_prevState         = "";
    m_currentState      = NULL;
    m_clientConfig      = NULL;
    m_Binder            = new Binder;
}

/** Initialize the game subsystem */
int GameManager::Init()
{
    if ( g_kernel )
        m_clientConfig = new ClientConfig( g_kernel->GetCvars(), m_Binder );

    SetKeyFocus( true );
    SetMouseFocus( true );
    return 0;
}

/** Update the current Game State */
void GameManager::Update(float  dt)
{
    // update the current state
    if ( m_currentState )
    {
        m_currentState->Update( dt );
    }
}

/** Shutdown each state */
void GameManager::Shutdown()
{
    // save off the config -- MOVE?
    if ( m_clientConfig ) 
        m_clientConfig->Save( "config.cfg", "%% This file is generated by Myriad3D, please DO NOT modify. Doing so may result in corrupting the game. %%\n\n" );

    std::string consoleName = g_kernel->GetConsole()->GetName();
    type_GameStates::iterator it = gameStates.begin();
    for(; it != gameStates.end(); )
    {
        if ( it->second->GetName() != consoleName ) // Shutdown each state
        {
            it->second->Shutdown();
            delete it->second;
        }
        ++it;
    }
    gameStates.clear();
}

/** Add a gamestate, and a game view */
void GameManager::AddState( IGameState* state )
{
    gameStates[ state->GetName() ] = state;     // Place the states on a stack

    // if no current state, make this current
    if ( !m_currentState )
    {
        m_currentState = state;
    }
    g_kernel->LPrintf( ("Added a GameState: " + state->GetName()).c_str() );
    g_kernel->LPrintf( "Reference number: %5d ", state->GetID() );
}


/** Remove a state from the stack */
void GameManager::RemoveState( IGameState* state )
{
    state->Exit();              // shutdown this state
    state->Shutdown();

    type_GameStates::iterator it = gameStates.begin();
    for ( ; it != gameStates.end(); it++ )
    {
        if ( it->second == state )
        {
            gameStates.erase( it );
            delete it->second;
            
            return;
        }   
    } 
}

/** Get the current State */
IGameState* GameManager::GetCurrentState()
{
    return m_currentState;
}


/** Activate a State */
void GameManager::SetState(const std::string stateName, bool stayActive )
{
    if ( stateName == "" ) return;

    m_prevState = m_current;        // save the old state
    m_current   = stateName;

    IGameState* newState = gameStates[ m_current ];
    if ( newState ) {
        // Exit the old state
        if ( m_currentState ) 
        {
            m_currentState->Exit();
            m_currentState->SetActive( stayActive );
            g_kernel->GetRenderer()->SetStateViewStatus( m_currentState->GetID(), stayActive );    // HACKS!!!
        }
        // get the current state
        m_currentState = newState;
        m_currentState->Start();

        
        g_kernel->GetRenderer()->SetStateViewStatus( m_currentState->GetID(), true ); // set the correct view
    }
}

/** Push a state */
void GameManager::PushState(const std::string stateName, bool stayActive )
{
    gameStack.push( stateName );
    SetState( stateName, stayActive );
}

/** Load the Previous State */
void GameManager::PopState(bool keepOldActive)
{   
    if ( !gameStack.empty() )
    {   
        gameStack.pop();
        if ( !gameStack.empty() )
            SetState( gameStack.top(), keepOldActive );
    }
}


    /** -------------------------------------------
            IKeyListener Interface
    ----------------------------------------------- **/

/** Get the Key pressed */
void GameManager::KeyPressed( const KeyEvent* keyEvent )
{
    Console* console = g_kernel->GetConsole();
    int key =  keyEvent->GetKey();
    /**
        The console has special presidence, it
        can be activated at any time, and can not be
        unbinded, therefore it is hardcoded
    */
    if ( key == MK_BACKQUOTE )
    {
        console->Toggle();
        if ( console->IsShowing() )
            PushState( console->GetName(), true );
        else
            PopState(true); 
        return;
    }

    /**
        By design, HotKeys are ALWAYS 
        enabled across states EXCEPT the console
    */
    if ( !console->IsShowing() )
        m_Binder->Exec( key );

    // pass the input down
    if ( m_currentState )
        m_currentState->KeyPressed( keyEvent );
}

/** Get the Key Released */
void GameManager::KeyReleased( const KeyEvent* keyEvent )
{
    // pass the input down
    if ( m_currentState )
        m_currentState->KeyReleased( keyEvent );
}

/** A mouse button was pressed */
void GameManager::MouseButtonPressed( MouseEvent* mEvent )
{
     // pass the input down
    if ( m_currentState )
        m_currentState->MouseButtonPressed( mEvent );
}

/** A mouse button was released */
void GameManager::MouseButtonReleased( MouseEvent* mEvent )
{
     // pass the input down
    if ( m_currentState )
        m_currentState->MouseButtonReleased( mEvent );
}

/** Mouse Moved Event */
void GameManager::MouseMotion( MouseEvent* mEvent )
{
     // pass the input down
    if ( m_currentState )
        m_currentState->MouseMotion( mEvent );
}

GameManager::~GameManager(void)
{
    //g_kernel->LPrintf("Closing GameManager...");
}
